#include "SeeThru.h"
#include "Ray.h"
#include "Scene.h"

SeeThru::SeeThru(float (*rIndex)(short)):
refIndex(rIndex)
{

}

SeeThru::~SeeThru()
{
}

Vector3 SeeThru::shade(const Ray& ray, const HitInfo& hit, char rayCount, const Scene& scene, int mode, Vector3 rayColor, bool diffuseRay) const
{
    if(refIndex && rayCount < MAX_REFLECTIONS)
	{
		//indexes of refraction
		float n1, n2;
		Vector3 norm;

		//Check if you're going from air to material
		if(dot(hit.N,ray.d)<0) {
			n1 = IOR_AIR;
			n2 = refIndex(-1);
		}
		//Otherwise going from material to air
		else 
		{
			n1 = refIndex(-1);
			n2 = IOR_AIR;
			norm = -1*hit.N;
		}

		float n3 = n1/n2;
		Vector3 w = -1.0*ray.d;
		float dotProd = dot(w,norm);
		
		Vector3 refraction = -1.0*(n3)*(w - dotProd*norm)-sqrt(1-((n3)*(n3))*(1-(dotProd*dotProd)))*norm;
		refraction.normalize();

		Ray newRay(hit.P, refraction);
		HitInfo newHitInfo;
		if (scene.trace(newHitInfo, newRay, epsilon))
		{
			Vector3 L = newHitInfo.material->shade(newRay, newHitInfo, (rayCount+1), scene, mode, rayColor);
			return L;
		}
	}

	return Vector3(0);
}

void SeeThru::handlePhoton(const Ray& ray, const HitInfo& hit, char rayCount, Vector3 photonFlux, const Scene& scene, int mode, LightPath *lp) const
{
    if(rayCount < MAX_REFLECTIONS)
	{
		//indexes of refraction
		float n1, n2;
		Vector3 norm;

		//Check if you're going from air to material
		if(dot(hit.N,ray.d)<0) {
			n1 = IOR_AIR;
			n2 = refIndex(-1);
		}
		//Otherwise going from material to air
		else
		{
			n1 = refIndex(-1);
			n2 = IOR_AIR;
			norm = -1*hit.N;
		}

		float n3 = n1/n2;
		Vector3 w = -1.0*ray.d;
		float dotProd = dot(w,norm);

		Vector3 refraction = -1.0*(n3)*(w - dotProd*norm)-sqrt(1-((n3)*(n3))*(1-(dotProd*dotProd)))*norm;
		refraction.normalize();

		Ray newRay(hit.P, refraction);
		HitInfo newHitInfo;
		if (scene.trace(newHitInfo, newRay, epsilon))
		{
			newHitInfo.material->handlePhoton(newRay, newHitInfo, rayCount+1, photonFlux, scene, mode, lp);
		}
	}
}
